/**
 * @file
 * Core library header file.
 *
 * Kisa provides spell checking as you type and displays the result in a small
 * window on your Desktop.
 *
 * Copyright (c) 2009 by Pete Black <theblackpeter@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * @author Pete Black <theblackpeter@gmail.com>
 */
#ifndef KISALIB_H
#define KISALIB_H

#include "aspelllib.h"
#include "x11lib.h"

/**
 * @class KisaLib
 * The KisaLib class provides access to library resources that interface
 * with external libraries, such as X11 and Aspell by inheriting from these base
 * classes. All external requests are made from here and then translated back
 * into internal data structures. These are then used by the main application
 * and worker thread.
 *
 * Even though the @em Singleton design pattern is used, make sure that the
 * library is properly initialized before making any global calls. This
 * is done by acquiring an instance via instance() and then calling
 * initialize(), like so:
 * @code
 *   KisaLib* kisaLib = KisaLib::instance();
 *   kisaLib->initialize();
 * @endcode
 *
 * After doing this, the library is fully initialized and calls can be
 * made from any location that has knowledge about KisaLib. For example, to
 * get a list of suggestions if a word is misspelled, one could do something
 * like this:
 *
 * @code
 *  #include "kisalib.h"
 *  ...
 *  QString myWord;
 *  QStringList suggestions;
 *  ...
 *  if(KisaLib::isMisspelled(myWord))
 *    suggestions = KisaLib::getSuggestions();
 *  ...
 * @endcode
 *
 * When subscribing to X11 events that originate from other windows on the
 * Desktop, these event masks are used:
 *  @li @c KeyPressMask
 *  @li @c SubstructureNotifyMask
 *  @li @c VisibilityChangeMask
 *
 * @c NoEventMask is used to remove notification subscriptions.
 *
 * The above listed event masks generate the following X11 events that are of
 * interest:
 *  @li @c KeyPress, for whenever a key is pressed in any window
 *  @li @c VisibilityNotify, for whenever our @em own application becomes
 *      obstructed or unobstructed
 *  @li @c CreateNotify, for whenever a new window is created
 *  @li @c MapNotify, for whenever a window is made visible
 *  @li @c ConfigureNotify, for whenever a window is reconfigured, for example
 *      when the user clicks in it
 *
 * These are translated to the following KisaEvent events:
 *  @li @c KeyPress to KisaEvent::KeyPress
 *  @li @c VisibilityNotify, @c CreateNotify and @c MapNotify to
 *      KisaEvent::WindowActivate
 *
 * When using the library for subscribing to X11 events, use
 * addNotification(const Window&, KisaEvent::Type type) in X11Lib, which uses
 * the KisaEvent type rather then changeNotification(const Window&, EventMask),
 * which uses the X11 event mask. The latter is intended for internal use.
 *
 * @code
 *  ...
 *  KisaEvent* kisaevent = KisaLib::nextEvent();
 *  addNotification(kisaevent->window(), KisaEvent::KeyPress);
 *  ...
 * @endcode
 *
 * @author Pete Black <theblackpeter@gmail.com>
 * @see Kisa
 * @see KisaThread
 * @see KisaEvent
 * @see X11Lib
 * @see AspellLib
 */
class KisaLib : public AspellLib, public X11Lib {

  public:
  /**
   * Destructor. Reverts back to the original X11 error handler, closes the
   * connection to the X11 server and destroys any dynamically created
   * objects.
   */
  virtual ~KisaLib();

  /**
   * Returns a string containing the location of the current country flag
   * pixmap, given by the two character ISO 3166 country code. If none is
   * found an empty string is returned.
   *
   * @param countryCode the two character country code in ISO 3166 format
   * @return the location of the pixmap, or an empty string, ""
   */
  QString getCountryFlagURL(QString countryCode);

  /**
   * Gets the current keyboard layout locale code in ISO 639 and ISO 3166
   * format.
   * For example, a default American English keyboard layout (sometimes
   * donate by the code "C") will return the locale code:
   * @c en_US.
   *
   * @warning This function may produces incorrect results on some systems.
   *
   * @bug kxkb stops updating the X11 keyboard layout whenever switching back
   * to and already seen layout.
   * This can be verified this using @c setxkbmap @c -print.
   *
   * @bug kxkb now (KDE 4.0.2) seems to have stopped updating layouts completely
   * so no keyboard layout change events are received. There is a hack in place
   * that will overcome this by polling the current keyboard layout on every new
   * word that is entered (at the first charater of that word).
   *
   * @bug On some systems QApplication::keyboardInputLocale() does not always
   * return the right layout. For instance, it may be needed to change the
   * layout twice using @c setxkbmap @c -layout @c \<layout\>  before
   * QApplication::keyboardInputLocale() returns the right layout.
   * This can be verified this using @c setxkbmap @c -print.
   *
   * @return the current keyboard layout locale code
   */
  QString getKeyboardInputLayout();

  /**
   * Uses Qt's locale system to make a best match for the locale code given the
   * country. This might not always be accurate as there are languages that are
   * spoken in several countries.
   *
   * These codes are 5 characters long specified by the ISO 639 and ISO
   * 3166 standards. The code is on the form @c language_COUNTRY.
   *
   * @param country the country to get the locale for
   * @return the best guess for the locale code
   * @see dictionaryCodesGuessed()
   */
  const QString guessLocale(const QString& country);

  /**
   * Initializes the library so that it is ready for use. If the library has
   * not been instantiated before, by calling instance(), it will be done
   * here.
   *
   * Parameters are just passed along and not manage here.
   * See the referencing functions for more detailes on the parameters.
   *
   * @note The library can be used first after this functions is called.
   *
   * @param iconspath the path to the icon pixmaps
   * @param flagspath the path to the flags icon pixmaps
   * @param dictionary the default dictionary to use in ISO 639 and ISO 3166
   * format
   * @param dictDir the main word list location
   * @param aspellPrefix the Aspell prefix directory
   * @param extraDicts the extra dictionaries to use
   */
  void initialize(const QString& iconspath = QString(),
                  const QString& flagspath = QString(),
                  const QString& dictionary = QString(),
                  const QString& dictDir = QString(),
                  const QString& aspellPrefix = QString(),
                  const QString& extraDicts = QString());

  /**
   * Accesses the current instance of the library or creates a new one if not
   * instantiated before. Classic @em Singleton design pattern approach.
   *
   * No restrictions are posed on @p displayString, as it's simply passed on
   * to the constructor if and when a new instance is created. If an instance
   * already exists @p displayString is ignored.
   *
   * @param displayString the X11 display, or ":0" if none is given
   * @return the current instance
   * @see KisaLib(QString)
   */
  static KisaLib* instance(const QString& displayString = QString());

  /**
   * Sets the flag icons resource path. If @p path is not given then
   * @c LOCALE_PATH is used, which by default is "/usr/share/locale/l10n"
   *
   * When all else fails, then the last path of the default
   * KDE locale path (given by "kde4-config --path locale") will be
   * used as a prefix.
   *
   * @param path the path to the flag icon pixmaps, or the default value will
   * be used if none is given
   */
  void setFlagsSearchPaths(QString path = QString());

  /**
   * Sets icons resource path, that is, where to look for icon pixmaps.
   *
   * If a faulty path or if none is given, then the current KDE user icon theme
   * path will be used. The path of "/usr/share/icons/<ICON_THEME>" is also
   * added, where @c ICON_THEME by default is "oxygen".
   *
   * Currently, only KDE support is available, so pass the icon location as a
   * command line argument if running under another window environment.
   *
   * @param path the path to the icon pixmaps, or default values will be used
   * if none is given
   */
  void setIconsSearchPaths(QString path = QString());

  protected:

  /**
   * Constructor. Creates a Singleton instance of the library and connects to
   * the X11 server display given by @p displayString. If If an incorrect or no
   * display is given the environment variable $DISPLAY will be used.
   * Failing that, the default display, ":0", will by used.
   *
   * @param displayString the X11 server display to connect to, if none is
   * given then the display specified in $DISPLAY will be used or ":0" if that
   * fails
   *
   * @see instance()
   */
  KisaLib(const QString& displayString = QString());

  /**
   * Uses kxkb to get the current keyboard by connecting over D-Bus. This
   * function will get the keyboard layout from kxkb which contains the
   * two-letter ISO 3166 code (and sometimes a variant in parenthesis).
   *
   * @return the current keyboard layout locale code
   *
   * @see getKeyboardInputLayout()
   * @see parseKeyboardLayout()
   */
  QString getKeyboardInputLayoutKxkb();

  /**
   * Parses the keyboard layout map @p keyboardLayoutMap to guess the
   * four-letter ISO language locale code. The language code contains the ISO
   * 3166 language and ISO 639 country codes on the format language_COUNTRY
   *
   * Will try to split the keyboard layout which is usually on the form
   * @em countryCode(variant). If the country code contains any underscores, "_",
   * then the first part will be used.
   *
   * @param keyboardLayout in pretty much any format
   *
   * @return and educated guess on the language locale for that keyboard
   *
   * @see getKeyboardInputLayoutKxkb()
   */
  const QString guessKeyboardLayoutFromMap(const QString& keyboardLayoutMap);

  /**
   * Initializes all member variables.
   *
   * This function will augment the base class function.
   */
  virtual void initMembers();

  private:

  /**
   * Pointer to the current instance of the library.
   *
   * @see instance()
   */
  static KisaLib* m_instance;
};
#endif
